{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "\n",
    "> 注意：\n",
    "> `python>=3.11` `langchain-core>=0.2.16`"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "d15080b27d5f1c67"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "from langchain_core.tools import tool\n",
    "from langchain_core.output_parsers import JsonOutputParser, StrOutputParser\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "import os\n",
    "from langchain_openai import ChatOpenAI\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "load_dotenv()\n",
    "llm = ChatOpenAI(\n",
    "    # 若没有配置环境变量，请用百炼API Key将下行替换为：api_key=\"sk-xxx\",\n",
    "    openai_api_key=os.getenv(\"DASHSCOPE_API_KEY\"),\n",
    "    openai_api_base=\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n",
    "    model_name=\"qwen-max\",\n",
    "    max_retries=0,\n",
    ")\n",
    "\n",
    "@tool\n",
    "async def special_summarization_tool(long_text: str) -> str:\n",
    "    \"\"\"A tool that summarizes input text using advanced techniques.\"\"\"\n",
    "    prompt = ChatPromptTemplate.from_template(\n",
    "        \"You are an expert writer. Summarize the following text in 10 words or less:\\n\\n{long_text}\"\n",
    "    )\n",
    "\n",
    "    def reverse(x: str):\n",
    "        return x[::-1]\n",
    "\n",
    "    chain = prompt | llm | StrOutputParser() | reverse\n",
    "    summary = await chain.ainvoke({\"long_text\": long_text})\n",
    "    return summary"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-10-31T03:32:38.416935Z",
     "start_time": "2024-10-31T03:32:36.571720Z"
    }
   },
   "id": "cb8e1a4c6d2b612d",
   "execution_count": 1
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "'.tsafkaerb neht ,stiftuo sesoohc yrraB ;swal thgilf yfed seeB'"
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "LONG_TEXT = \"\"\"\n",
    "NARRATOR:\n",
    "(Black screen with text; The sound of buzzing bees can be heard)\n",
    "According to all known laws of aviation, there is no way a bee should be able to fly. Its wings are too small to get its fat little body off the ground. The bee, of course, flies anyway because bees don't care what humans think is impossible.\n",
    "BARRY BENSON:\n",
    "(Barry is picking out a shirt)\n",
    "Yellow, black. Yellow, black. Yellow, black. Yellow, black. Ooh, black and yellow! Let's shake it up a little.\n",
    "JANET BENSON:\n",
    "Barry! Breakfast is ready!\n",
    "BARRY:\n",
    "Coming! Hang on a second.\n",
    "\"\"\"\n",
    "\n",
    "await special_summarization_tool.ainvoke({\"long_text\": LONG_TEXT})"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-10-31T03:33:06.920468Z",
     "start_time": "2024-10-31T03:33:05.272569Z"
    }
   },
   "id": "d7a0a09b6514df17",
   "execution_count": 2
  },
  {
   "cell_type": "markdown",
   "source": [
    "如果您想从聊天模型而不是完整的工具中访问原始输出，您可以尝试使用astream_events()方法并查找on_chat_model_end事件。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "80f5dc3cd2979c65"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={}, response_metadata={}, id='run-c1674c64-b16d-4f87-b779-f32bdb6569fb')}, 'run_id': 'c1674c64-b16d-4f87-b779-f32bdb6569fb', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['eabb3603-5cba-424e-ad23-5ddd68c20c57', 'd85f0281-eb44-43b0-b9d9-bb3fd83caac9']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='Bees', additional_kwargs={}, response_metadata={}, id='run-c1674c64-b16d-4f87-b779-f32bdb6569fb')}, 'run_id': 'c1674c64-b16d-4f87-b779-f32bdb6569fb', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['eabb3603-5cba-424e-ad23-5ddd68c20c57', 'd85f0281-eb44-43b0-b9d9-bb3fd83caac9']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=' defy', additional_kwargs={}, response_metadata={}, id='run-c1674c64-b16d-4f87-b779-f32bdb6569fb')}, 'run_id': 'c1674c64-b16d-4f87-b779-f32bdb6569fb', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['eabb3603-5cba-424e-ad23-5ddd68c20c57', 'd85f0281-eb44-43b0-b9d9-bb3fd83caac9']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=' flight laws; Barry picks', additional_kwargs={}, response_metadata={}, id='run-c1674c64-b16d-4f87-b779-f32bdb6569fb')}, 'run_id': 'c1674c64-b16d-4f87-b779-f32bdb6569fb', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['eabb3603-5cba-424e-ad23-5ddd68c20c57', 'd85f0281-eb44-43b0-b9d9-bb3fd83caac9']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=' clothes, then breakfast', additional_kwargs={}, response_metadata={}, id='run-c1674c64-b16d-4f87-b779-f32bdb6569fb')}, 'run_id': 'c1674c64-b16d-4f87-b779-f32bdb6569fb', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['eabb3603-5cba-424e-ad23-5ddd68c20c57', 'd85f0281-eb44-43b0-b9d9-bb3fd83caac9']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='.', additional_kwargs={}, response_metadata={}, id='run-c1674c64-b16d-4f87-b779-f32bdb6569fb')}, 'run_id': 'c1674c64-b16d-4f87-b779-f32bdb6569fb', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['eabb3603-5cba-424e-ad23-5ddd68c20c57', 'd85f0281-eb44-43b0-b9d9-bb3fd83caac9']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={}, response_metadata={'finish_reason': 'stop', 'model_name': 'qwen-max'}, id='run-c1674c64-b16d-4f87-b779-f32bdb6569fb')}, 'run_id': 'c1674c64-b16d-4f87-b779-f32bdb6569fb', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['eabb3603-5cba-424e-ad23-5ddd68c20c57', 'd85f0281-eb44-43b0-b9d9-bb3fd83caac9']}\n"
     ]
    }
   ],
   "source": [
    "stream = special_summarization_tool.astream_events(\n",
    "    {\"long_text\": LONG_TEXT}, version=\"v2\"\n",
    ")\n",
    "\n",
    "async for event in stream:\n",
    "    if event[\"event\"] == \"on_chat_model_stream\":\n",
    "        # Never triggers in python<=3.10!\n",
    "        print(event)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-10-31T03:41:25.637943Z",
     "start_time": "2024-10-31T03:41:23.653512Z"
    }
   },
   "id": "8547f31672dce6da",
   "execution_count": 8
  },
  {
   "cell_type": "markdown",
   "source": [
    "您会发现（除非您使用的是python>=3.11运行此指南）运行中并没有发现聊天模型事件！\n",
    "\n",
    "这是因为上面的示例没有将工具的配置对象传递到内部链中。为了解决这个问题，请重新定义您的工具，使其接受类型为RunnableConfig的特殊参数（有关更多详细信息，请参阅此指南）。当执行它时，您还需要将该参数传递到内部链中："
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "d86ea439de9be33a"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "from langchain_core.runnables import RunnableConfig\n",
    "\n",
    "\n",
    "@tool\n",
    "async def special_summarization_tool_with_config(\n",
    "    long_text: str, config: RunnableConfig\n",
    ") -> str:\n",
    "    \"\"\"A tool that summarizes input text using advanced techniques.\"\"\"\n",
    "    prompt = ChatPromptTemplate.from_template(\n",
    "        \"You are an expert writer. Summarize the following text in 10 words or less:\\n\\n{long_text}\"\n",
    "    )\n",
    "\n",
    "    def reverse(x: str):\n",
    "        return x[::-1]\n",
    "\n",
    "    chain = prompt | llm | StrOutputParser() | reverse\n",
    "    # Pass the \"config\" object as an argument to any executed runnables\n",
    "    summary = await chain.ainvoke({\"long_text\": long_text}, config=config)\n",
    "    return summary"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-10-31T03:37:31.348359Z",
     "start_time": "2024-10-31T03:37:31.324681Z"
    }
   },
   "id": "23aa67c4962a68ea",
   "execution_count": 4
  },
  {
   "cell_type": "markdown",
   "source": [
    "现在，使用你的新工具，尝试与之前相同的astream_events()调用。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "7a12f50667532ea8"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={}, response_metadata={}, id='run-a85f2161-0da9-4e52-8d14-f73b75c24dcd')}, 'run_id': 'a85f2161-0da9-4e52-8d14-f73b75c24dcd', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['d844c705-2779-470b-afea-073e4e68d5a8', '50fa76f4-d5e4-40ac-9e70-bf94fe04872c']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='Bees', additional_kwargs={}, response_metadata={}, id='run-a85f2161-0da9-4e52-8d14-f73b75c24dcd')}, 'run_id': 'a85f2161-0da9-4e52-8d14-f73b75c24dcd', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['d844c705-2779-470b-afea-073e4e68d5a8', '50fa76f4-d5e4-40ac-9e70-bf94fe04872c']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=' defy', additional_kwargs={}, response_metadata={}, id='run-a85f2161-0da9-4e52-8d14-f73b75c24dcd')}, 'run_id': 'a85f2161-0da9-4e52-8d14-f73b75c24dcd', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['d844c705-2779-470b-afea-073e4e68d5a8', '50fa76f4-d5e4-40ac-9e70-bf94fe04872c']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=' flight', additional_kwargs={}, response_metadata={}, id='run-a85f2161-0da9-4e52-8d14-f73b75c24dcd')}, 'run_id': 'a85f2161-0da9-4e52-8d14-f73b75c24dcd', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['d844c705-2779-470b-afea-073e4e68d5a8', '50fa76f4-d5e4-40ac-9e70-bf94fe04872c']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=' laws; Barry chooses', additional_kwargs={}, response_metadata={}, id='run-a85f2161-0da9-4e52-8d14-f73b75c24dcd')}, 'run_id': 'a85f2161-0da9-4e52-8d14-f73b75c24dcd', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['d844c705-2779-470b-afea-073e4e68d5a8', '50fa76f4-d5e4-40ac-9e70-bf94fe04872c']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=' outfits, then breakfast', additional_kwargs={}, response_metadata={}, id='run-a85f2161-0da9-4e52-8d14-f73b75c24dcd')}, 'run_id': 'a85f2161-0da9-4e52-8d14-f73b75c24dcd', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['d844c705-2779-470b-afea-073e4e68d5a8', '50fa76f4-d5e4-40ac-9e70-bf94fe04872c']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='.', additional_kwargs={}, response_metadata={}, id='run-a85f2161-0da9-4e52-8d14-f73b75c24dcd')}, 'run_id': 'a85f2161-0da9-4e52-8d14-f73b75c24dcd', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['d844c705-2779-470b-afea-073e4e68d5a8', '50fa76f4-d5e4-40ac-9e70-bf94fe04872c']}\n",
      "{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={}, response_metadata={'finish_reason': 'stop', 'model_name': 'qwen-max'}, id='run-a85f2161-0da9-4e52-8d14-f73b75c24dcd')}, 'run_id': 'a85f2161-0da9-4e52-8d14-f73b75c24dcd', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'ls_provider': 'openai', 'ls_model_name': 'qwen-max', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['d844c705-2779-470b-afea-073e4e68d5a8', '50fa76f4-d5e4-40ac-9e70-bf94fe04872c']}\n"
     ]
    }
   ],
   "source": [
    "stream = special_summarization_tool_with_config.astream_events(\n",
    "    {\"long_text\": LONG_TEXT}, version=\"v2\"\n",
    ")\n",
    "\n",
    "async for event in stream:\n",
    "    if event[\"event\"] == \"on_chat_model_stream\":\n",
    "        print(event, end=\"\\n\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-10-31T03:41:08.445403Z",
     "start_time": "2024-10-31T03:41:07.171666Z"
    }
   },
   "id": "5ce061762dd0d853",
   "execution_count": 7
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
